/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.wse.impl;

import cgl.narada.wsinfra.exception.ProcessingException;
import cgl.narada.wsinfra.schemas.addressing.ActionDocument;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.addressing.FromDocument;
import cgl.narada.wsinfra.schemas.addressing.RelatesToDocument;
import cgl.narada.wsinfra.schemas.eventing.GetStatusResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.IdentifierDocument;
import cgl.narada.wsinfra.schemas.eventing.RenewResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscriptionEndDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.util.SoapMessageAlteration;
import cgl.narada.wsinfra.wsa.AddressingHeaders;
import cgl.narada.wsinfra.wsa.WsaEnvelopeCreator;
import cgl.narada.wsinfra.wsa.WsaEprCreator;
import cgl.narada.wsinfra.wsa.WsaEprRules;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;
import cgl.narada.wsinfra.wse.WseActions;
import cgl.narada.wsinfra.wse.WseQNames;
import cgl.narada.wsinfra.wse.WseResponseCreator;
/**
   This is a utility class which create various responses based on the
   specified parameters. This is typically used by the source and the
   subscriptionManager.

   @author Shrideep Pallickara
   $Date: 2005/07/29 22:41:30 $
   $Revision: 1.5 $
*/

public class WseResponseCreatorImpl implements WseResponseCreator {
  private static final WseResponseCreator instance =
  new WseResponseCreatorImpl();

  private WseQNames wseQNames;
  private WseActions wseActions;
  private WsaEprCreator wsaEprCreator;
  private WsaEprRules wsaEprRules;
  private WsaEnvelopeCreator wsaEnvelopeCreator;
  private SoapMessageAlteration soapMessageAlteration;

  private String moduleName = "WseResponseCreator: ";

  private WseResponseCreatorImpl() {
    wseQNames = WseQNames.getInstance();
    wseActions = WseActions.getInstance();

    soapMessageAlteration = SoapMessageAlteration.getInstance();
    wsaEprCreator = WsaProcessingFactory.getWsaEprCreator();
    wsaEprRules = WsaProcessingFactory.getWsaEprRules();
    wsaEnvelopeCreator = WsaProcessingFactory.getWsaEnvelopeCreator();
  }



  public static WseResponseCreator getInstance() {
    return instance;
  }
 

   /** Create the SOAP envelope with the specified subscribe response. This
      envelope's destination is the Sink which generated the original request
      message. */
  public EnvelopeDocument
  createSubscribeResponse(EndpointReferenceType sinkEpr,
			  EndpointReferenceType sourceEpr,
			  RelatesToDocument relatesTo,
			  SubscribeResponseDocument subscribeResponseDocument)
    throws ProcessingException {

    EndpointReferenceType to = sinkEpr;
    if (to == null) {
      String errorReport = moduleName + "The specified sinkEPR in the " +
	"creation of the [SubscribeResponse] Envelope is NULL!";
      throw new ProcessingException(errorReport);
    }
    
    
    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(sourceEpr);

    ActionDocument action = wseActions.getSubscribeResponseAction();
    //    RelatesToDocument relatesTo = initializeRelatesTo(requestHeaders);

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(to, from, action, relatesTo);

    soapMessageAlteration.addToSoapBody(envelopeDocument,
					subscribeResponseDocument);
    return envelopeDocument;
  }


  /** Create the SOAP envelope with the specified subscribe response AND the
      subscribe original request. This envelope's destination is the
      SubscriptionManager for the source in question. */
  public EnvelopeDocument
  createSubscribeResponseToSM(EndpointReferenceType subscriptionManagerEpr,
			      EndpointReferenceType sourceEpr,
			      SubscribeDocument subscribeDocument,
			      SubscribeResponseDocument subResponseDocument) 
    throws ProcessingException {
    if (subscriptionManagerEpr == null) {
      String errorReport = moduleName + "Specified SubscriptionManagerEPR " +
	"destination in the creation of [SubscribeResponse] Envelope to the" +
	"SubscriptionManager is NULL!";
      throw new ProcessingException(errorReport);
    }

    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(sourceEpr);

    ActionDocument action = wseActions.getSubscribeResponseAction();
    RelatesToDocument relatesTo = null;

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(subscriptionManagerEpr /*to*/,
					    from, action, relatesTo);

    soapMessageAlteration.addToSoapBody(envelopeDocument, subResponseDocument);
    soapMessageAlteration.addToSoapBody(envelopeDocument, subscribeDocument);

    return envelopeDocument;
  }


  /** Create the SOAP envelope with the specified renew response. This
      envelope's destination is the sink which originated the message. */
  public EnvelopeDocument
  createRenewResponse(EndpointReferenceType sinkEpr,
		      EndpointReferenceType subscriptionManagerEpr,
		      RelatesToDocument relatesTo,
		      RenewResponseDocument renewResponseDocument) 
    throws ProcessingException  {
    EndpointReferenceType to = sinkEpr;

    if (to == null) {
      String errorReport = moduleName + "The specified sinkEPR in the " +
	"creation of the [RenewResponse] Envelope is NULL!";
      throw new ProcessingException(errorReport);
    }


    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(subscriptionManagerEpr);

    ActionDocument action = wseActions.getRenewResponseAction();
    //RelatesToDocument relatesTo = initializeRelatesTo(requestHeaders);

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(to, from, action, relatesTo);

    soapMessageAlteration.addToSoapBody(envelopeDocument,
					renewResponseDocument);
    return envelopeDocument;
  }




  /** Create the SOAP envelope with the specified renew response. This
      envelope's destination is the source which notify's the relevant sink. */
  public EnvelopeDocument
  createRenewResponseToSource(EndpointReferenceType sourceEpr,
			      EndpointReferenceType subscriptionManagerEpr,
			      String subscriptionIdentifier,
			      RenewResponseDocument renewResponseDocument) 
    throws ProcessingException {
  
    if (sourceEpr == null) {
      String errorReport = moduleName + "The specified SourceEPR in the " +
	"creation of the [RenewResponse] Envelope to Source is NULL!";
      throw new ProcessingException(errorReport);
    }

    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(subscriptionManagerEpr);

    ActionDocument action = wseActions.getRenewResponseAction();
    RelatesToDocument relatesTo = null;

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(sourceEpr, from,
					    action, relatesTo);

    IdentifierDocument idDocument =
      initializeIdentifier(subscriptionIdentifier);

    soapMessageAlteration.addToSoapHeader(envelopeDocument, idDocument);
    soapMessageAlteration.addToSoapBody(envelopeDocument,
					renewResponseDocument);
    return envelopeDocument;
  }





  /** Create the SOAP envelope with the specified getStatus response. This
      envelope's destination is the sink which originated the message. */
  public EnvelopeDocument
  createGetStatusResponse(EndpointReferenceType sinkEpr,
			  EndpointReferenceType subscriptionManagerEpr,
			  RelatesToDocument relatesTo,
			  GetStatusResponseDocument getStatusResponseDocument)
    throws ProcessingException {

    EndpointReferenceType to = sinkEpr;
    if (to == null) {
      String errorReport = moduleName + "The specified sinkEPR in the " +
	"creation of the [GetStatusResponse] Envelope is NULL!";
      throw new ProcessingException(errorReport);
    }

    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(subscriptionManagerEpr);

    ActionDocument action = wseActions.getGetStatusResponseAction();
    //RelatesToDocument relatesTo = initializeRelatesTo(requestHeaders);

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(to, from, action, relatesTo);

    soapMessageAlteration.addToSoapBody(envelopeDocument,
					getStatusResponseDocument);
    return envelopeDocument;
  }


  /** Create the SOAP envelope with the specified getStatus response. This
      envelope's destination is the sink which originated the message. */
  public EnvelopeDocument
  createUnsubscribeResponse(EndpointReferenceType sinkEpr,
			    EndpointReferenceType subscriptionManagerEpr,
			    RelatesToDocument relatesTo) 
    throws ProcessingException {

    EndpointReferenceType to = sinkEpr;
    if (to == null) {
      String errorReport = moduleName + "The specified sinkEPR in the " +
	"creation of the [UnsubscribeResponse] Envelope is NULL!";
      throw new ProcessingException(errorReport);
    }

    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(subscriptionManagerEpr);

    ActionDocument action = wseActions.getUnsubscribeResponseAction();
    //    RelatesToDocument relatesTo = initializeRelatesTo(requestHeaders);

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(to, from, action, relatesTo);

    return envelopeDocument;
  }


   /** Create the SOAP envelope with the specified getStatus response. This
      envelope's destination is the source for the sink in question. */
  public EnvelopeDocument
  createUnsubscribeResponseToSource(EndpointReferenceType sourceEpr,
				    EndpointReferenceType subscriptionMgrEpr,
				    String subscriptionIdentifier)
    throws ProcessingException {
    
    if (sourceEpr == null) {
      String errorReport = moduleName + "The specified SourceEPR in the " +
	"creation of the [RenewResponse] Envelope to Source is NULL!";
      throw new ProcessingException(errorReport);
    }

    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(subscriptionMgrEpr);

    ActionDocument action = wseActions.getUnsubscribeResponseAction();
    RelatesToDocument relatesTo = null;

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(sourceEpr, from,action, relatesTo);

    IdentifierDocument idDocument =
      initializeIdentifier(subscriptionIdentifier);
    
    soapMessageAlteration.addToSoapHeader(envelopeDocument, idDocument);

    return envelopeDocument;

  }



  /** Creates a SOAP envelope with the subscription end document */
  public EnvelopeDocument
  createSubscriptionEnd(EndpointReferenceType destinationEpr,
			EndpointReferenceType sourceEpr,
			SubscriptionEndDocument subscriptionEndDocument) 
  throws ProcessingException {

    if (destinationEpr == null) {
      String errorReport = moduleName +  "The destination for the " + 
	"[SubscriptionEnd] envelope is NULL.";

    }

    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(sourceEpr);

    ActionDocument action = wseActions.getSubscriptionEndAction();
    RelatesToDocument relatesTo = null;

    EnvelopeDocument envelopeDocument =
      wsaEnvelopeCreator.createSoapEnvelope(sourceEpr, from,
					    action, relatesTo);

    soapMessageAlteration.addToSoapBody(envelopeDocument,
					subscriptionEndDocument);
    return envelopeDocument;
  }




  /** Try and the initialize the EPR to send a response message to. This
      is typically used to initialize the [wsa:To] element. The addressing
      headers that are passed here are the headers that were constructed based
      on the original request that came in previously. So this method will 
      look for the [wsa:ReplyTo] or [wsa:From] elements to construct the 
      responses. */
  public EndpointReferenceType 
  getSendResponseTo(AddressingHeaders requestHeaders, 
		    EndpointReferenceType alternateEPR, 
		    String requestType) 
    throws ProcessingException {
    
    EndpointReferenceType to = wsaEprRules.sendTo(requestHeaders);
    
    if (to != null) {
      return to;
    }
    
    String errorReport = null;
    if (to == null) {
      errorReport = moduleName + "The " + requestType + " came in without the"
	+ " appropriate [wsa:ReplyTo] or [wsa:From] elements. "; 
      System.out.println(errorReport + "Will try and use alternate EPR");
    }
    
    if (alternateEPR == null) {
      errorReport += "Furthermore, the available alternateEPR is also NULL!\n";
      throw new ProcessingException(errorReport);
    }
    
    return alternateEPR;
  } 



  /** Initializes the relates to element appropriately, based on whether there
      is a messageID in the requestHeaders. This will return a NULL if there
      is no MessageID within the AddressingHeaders. */
  public RelatesToDocument
  getResponseRelatesTo(AddressingHeaders requestHeaders) {
    RelatesToDocument relatesTo = null;
    if (requestHeaders.hasMessageID()) {
      String messageId =
	requestHeaders.getMessageID().getMessageID().getStringValue();
      relatesTo = RelatesToDocument.Factory.newInstance();
      relatesTo.addNewRelatesTo().setStringValue(messageId);
    }

    return relatesTo;
  }



  /** Get the identifier document initialized based on the specified
      identifier */
  private IdentifierDocument initializeIdentifier(String identifier) {
    IdentifierDocument idDocument = IdentifierDocument.Factory.newInstance();
    idDocument.setIdentifier(identifier);
    return idDocument;
  }


  


  /** Computes the destination to send a Message To based on the specified
      Addressing Headers */
  private EndpointReferenceType
  initializeTo(AddressingHeaders requestHeaders) {
    EndpointReferenceType to = null;

    boolean toInitialized=false;
    if (requestHeaders.hasReplyTo()) {
      to = requestHeaders.getReplyTo().getReplyTo();
      toInitialized=true;
    }

    if (!toInitialized) {
      if (requestHeaders.hasFrom()) {
	to = requestHeaders.getFrom().getFrom();
	toInitialized=true;
      }
    }

    if (to == null) {
      System.out.println(moduleName +
			 "No destination to Send (To) has been specified");
    }

    return to;
  }
}


















































































